/**
 * huize Service Inc
 * All Rights Reserved @2018
 */
package com.huize.zhike.framework.common.util;

import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * 描述:
 *
 * @author tianyuliang
 * @version $Id: NumberUtils.java, v0.1 2020/6/5
 */
public class NumberUtils {

    /**
     * 整数0
     */
    public static final BigDecimal NUMBER_ZERO = new BigDecimal(0);
    /**
     * 0为此位置不足用0补齐 #为此位置不足就空着
     */
    private static final DecimalFormat decimalFormat = new DecimalFormat("0.00#");

    /**
     * 0为此位置不足用0补齐 #为此位置不足就空着
     */
    public static final DecimalFormat zeroFormat = new DecimalFormat("0.0");
    /**
     * 千分位数字 格式化
     */
    public static final DecimalFormat numberFormat = new DecimalFormat("#,##0");
    /**
     * 百分比+小数点 格式化
     * （# 如果对应位置上没有数字，则保持原样（不用补）；如果最前、后为0，则保持为空）
     */
    public static final DecimalFormat percentFormat = new DecimalFormat("#,##0.0");
    /**
     * 小数点后的位数
     */
    public static final int scale = 2;
    /**
     * 除法的结果 保留小数点位数, 如果不设置将可能出现无限循环小数
     */
    public static final int roundingMode = 6;

    /**
     * 构建默认值
     */
    public static BigDecimal defaultBigDecimal() {
        BigDecimal value = new BigDecimal("0.00");
        return value;
    }

    /**
     * 提供精确的加法运算
     *
     * @param value1 被加数
     * @param value2 加数
     * @return 两个参数的和
     */
    public static double add(Double value1, Double value2) {
        BigDecimal b1 = new BigDecimal(value1 == null ? 0D : value1);
        BigDecimal b2 = new BigDecimal(value2 == null ? 0D : value2);
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的加法运算
     *
     * @param b1 被加数
     * @param b2 加数
     * @return 两个参数的和
     */
    public static BigDecimal add(BigDecimal b1, BigDecimal b2) {
        BigDecimal zero = new BigDecimal("0");
        BigDecimal a1 = b1 != null ? b1 : zero;
        BigDecimal a2 = b2 != null ? b2 : zero;
        BigDecimal result = a1.add(a2);
        return result;
    }

    /**
     * 提供精确的减法运算
     *
     * @param value1 减数
     * @param value2 被减数
     * @return 两个参数的差
     */
    public static double subtract(Double value1, Double value2) {
        BigDecimal b1 = new BigDecimal(value1 == null ? 0D : value1);
        BigDecimal b2 = new BigDecimal(value2 == null ? 0D : value2);
        return b1.subtract(b2).doubleValue();
    }


    /**
     * 提供精确的乘法运算
     *
     * @param value1 乘数
     * @param value2 乘数
     * @return 两个参数的乘
     */
    public static double multiply(Double value1, Double value2) {
        BigDecimal b1 = new BigDecimal(value1 == null ? 0D : value1);
        BigDecimal b2 = new BigDecimal(value2 == null ? 0D : value2);
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供精确的除法运算（注意结果为无穷数）
     *
     * @param value1 除数
     * @param value2 被除数
     * @return 两个参数的商
     */
    public static double divide(BigDecimal value1, Integer value2) {
        Double result = 0D;
        BigDecimal b1 = value1 == null ? new BigDecimal(0) : value1;
        BigDecimal b2 = new BigDecimal(value2 == null ? 0D : value2);

        boolean ok1 = b1 == null || b2 == null;
        boolean ok2 = ok1 || Double.isNaN(b1.doubleValue()) || Double.valueOf(b1.doubleValue()).isInfinite();
        boolean ok3 = ok1 || Double.isNaN(value2.doubleValue()) || Double.valueOf(value2.doubleValue()).isInfinite();
        boolean ok4 = ok1 || b1.doubleValue() == 0D || b2.doubleValue() == 0D;
        if (ok2 || ok3 || ok4) {
            return result;
        }
        result = b1.divide(b2, roundingMode, BigDecimal.ROUND_HALF_DOWN).doubleValue();
        return result;
    }

    /**
     * 提供精确的除法运算（注意结果为无穷数）
     *
     * @param value1 除数
     * @param value2 被除数
     * @return 两个参数的商
     */
    public static double divide(Double value1, Double value2) {
        Double result = 0D;
        BigDecimal b1 = new BigDecimal(value1 == null ? 0D : value1);
        BigDecimal b2 = new BigDecimal(value2 == null ? 0D : value2);

        boolean ok1 = b1 == null || b2 == null;
        boolean ok2 = ok1 || Double.isNaN(value1) || Double.valueOf(value1).isInfinite();
        boolean ok3 = ok1 || Double.isNaN(value2) || Double.valueOf(value2).isInfinite();
        boolean ok4 = ok1 || b1.doubleValue() == 0D || b2.doubleValue() == 0D;
        if (ok2 || ok3 || ok4) {
            return result;
        }
        result = b1.divide(b2, roundingMode, BigDecimal.ROUND_HALF_DOWN).doubleValue();
        return result;
    }

    /**
     * 计算两数字相除的结果百分比 <br/>
     * 例如计算结果是87则表示87%, 计算结果是490则表示490%
     */
    public static Double percent(Double value1, Double value2) {
        Double percent = 0D;
        if (value1 == null || value2 == null || value2 == 0D || value1 == 0D) {
            return percent;
        }

        BigDecimal b1 = new BigDecimal(value1);
        BigDecimal b2 = new BigDecimal(value2);
        BigDecimal b3 = new BigDecimal("100");
        BigDecimal value = b1.divide(b2, roundingMode, BigDecimal.ROUND_HALF_DOWN); //百分比数字,需要扩大100倍
        percent = round(value.multiply(b3).doubleValue(), scale);
        return percent;
    }

    /**
     * 计算两数字相除的结果百分比 <br/>
     * 例如计算结果是87则表示87%, 计算结果是490则表示490%
     */
    public static Double percent(BigDecimal b1, BigDecimal b2) {
        Double percent = 0D;
        boolean ok1 = b1 == null || b2 == null;
        boolean ok2 = ok1 || Double.isNaN(b1.doubleValue()) || Double.valueOf(b1.doubleValue()).isInfinite();
        boolean ok3 = ok1 || Double.isNaN(b2.doubleValue()) || Double.valueOf(b2.doubleValue()).isInfinite();
        boolean ok4 = ok1 || b1.doubleValue() == 0D || b2.doubleValue() == 0D;
        if (ok2 || ok3 || ok4) {
            return percent;
        }
        BigDecimal b3 = new BigDecimal("100");
        BigDecimal value = b1.divide(b2, roundingMode, BigDecimal.ROUND_HALF_DOWN); //百分比数字,需要扩大100倍
        percent = round(value.multiply(b3).doubleValue(), scale);
        return percent;
    }

    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param value 需要四舍五入的数字
     * @return 四舍五入后的结果
     */
    public static Double round(Double value) {
        return round(value, scale);
    }

    /**
     * 提供精确的小数位四舍五入处理。
     *
     * @param value 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static Double round(Double value, int scale) {
        if (scale < 0) {
            throw new IllegalArgumentException("the scale must be a positive integer or zero");
        }
        if (Double.isNaN(value) || Double.valueOf(value).isInfinite()) {
            return 0D;
        }
        BigDecimal decimal = new BigDecimal(value);
        Double result = decimal.divide(new BigDecimal("1"), scale, BigDecimal.ROUND_HALF_UP).doubleValue();
        return result;
    }

    /**
     * 小数点保留2位,不足2位则补0
     * 链接 https://blog.csdn.net/CNDNSNNN/article/details/80390377
     *
     * @param value
     * @return
     */
    public static String format(Double value) {
        if (value == null || value == 0 || Double.isNaN(value) || Double.valueOf(value).isInfinite()) {
            return "0.0";
        }
        boolean ok = Math.abs(value) < 1D;
        if (ok) {
            return zeroFormat.format(value);
        }
        String result = numberFormat.format(Math.round(value));
        return result;
    }

    /**
     * 除100%以外，百分比都保留一位小数，如56.1%
     */
    public static String formatPercent(Double value) {
        if (value == null || value == 0 || Double.isNaN(value) || Double.valueOf(value).isInfinite()) {
            return "0.0";
        }
        String result = percentFormat.format(value);
        return result;
    }

    /**
     * 计算百分比,扩大100倍，百分比都保留一位小数，如56.1%
     */
    public static String format100Percent(BigDecimal value) {
        if (value == null || value.doubleValue() == 0 || Double.isNaN(value.doubleValue()) || Double.valueOf(value.doubleValue()).isInfinite()) {
            return "0.0";
        }
        BigDecimal divide = value.multiply(new BigDecimal(100));
        String result = NumberUtils.formatPercent(divide.doubleValue());
        return result;
    }

    public static void main(String[] args) {
        Double value1 = 0.45D;
        Double value2 = 0.72D;
        Double percent = percent(value1, value2);
        System.out.println(percent);
        System.out.println(zeroFormat.format(percent));
        System.out.println(format(value1));

        Double value3 = 1235632D;
        System.out.println(numberFormat.format(value3));
        System.out.println(format(value3));

        Double value6 = 123D;
        System.out.println(numberFormat.format(value6));
        System.out.println(format(value6));

        Double value4 = 1235632.2834D;
        System.out.println(percentFormat.format(value4));
        System.out.println(formatPercent(value4));

        Double value5 = 40.0D;
        System.out.println(percentFormat.format(value5));
        System.out.println(formatPercent(value5));
    }

}
